/**
 * @file session.h
 * @brief Specifica una struttura dati per comunicare con sessioni diverse dell'utente.
 *
 * Complete description of this file.
 *
 * @date Mar 18, 2012
 * @author Francesco Corvino
 */

#ifndef SESSION_H_
#define SESSION_H_

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "../MemObj/hiddenType.h"
#include "../MemObj/dynArray.h"
#include "../MemObj/cmap.h"

#define LOG_SESSION_NAME "session"

#define SESSION_BUFFER_MESSAGE BUFSIZ

/**
 * @brief Struttura che definisce l'interfaccia di una comunicazione tra host.
 *
 * Definisce il subject del pattern Observer, nell'entità è stato anche racchiuso
 * lo stato della comunicazione, cioè l'entità che rappresenenta gli ultimi messaggi scambiati.
 *
 * @see ElaborationEntity struttura coinvolta nelle comunicazioni.
 */
typedef struct HostSession_ {

	/**
	 * @brief attributo necessario per consentire alle elaborazioni di condividere dei dati
	 * all'interno della sessione
	 */
	CMap attributes;

	/**
	 * @brief attributo della sessione utilizzato per memorizzare dati specifici della tipologia di comunicazione.
	 *
	 * Sono utilizzati per fornire all'entità implementatrice della sessione uno strumento di memorizzazione dei dati
	 * di comunicazione.
	 */
	HiddenType dataSession;

	/**
	 * @brief intero che indica se la sessione è in attesa di essere letta.
	 */
	int isWaiting;

	/**
	 * @brief è un elenco di tutte le thread correlate con la sessione.
	 */
	DynArray threadsForSession;

	/**
	 * @brief puntatore a funzione che restituisce il file descriptor in lettura per la sessione.
	 */
	int (*getReadFd)(HiddenType*);

	/**
	 * @brief puntatore a funzione che restituisce il file descriptor in scrittura per la sessione.
	 */
	int (*getWriteFd)(HiddenType*);

	/**
	 * @brief mutex che permette di sincronizzare le letture.
	 */
	pthread_mutex_t syncReads;

	/**
	 * @brief mutex che permette di sincronizzare le scritture.
	 */
	pthread_mutex_t syncWrites;

	/**
	 * @brief mutex che permette la sincronizzazione delle operazioni con le elaborazioni.
	 */
	pthread_mutex_t syncElaborations;

	/**
	 * @brief effettua le operazioni di chiusura della sessione.
	 */
	void (*close)(HiddenType*);

	/**
	 * @brief utilizzata per effettuare le operazioni di aggiornamento della sessione.
	 */
	void (*update)(void);

	/**
	 * @brief intero che identifica la comunicazione tra le altre.
	 *
	 * Di solito assume il valore del pid con cui si comunica.
	 */
	int keySession;
} HostSession;

/**
 * @brief Struttura che definisce un'entità osservatrice di una comunicazione tra host.
 *
 * Le entità coinvolte posso essere elaborazioni dovute a richieste da thread interni al processo oppure
 * la main thread che opera per conto di altri processi.
 *
 * @see HostSession struttura che definisce una comunicazione.
 */
typedef struct elaborationEntity {
	int typeOfElaboration;

	/**
	 * @brief Attributo che permette di estendere le proprietà della classe.
	 */
	HiddenType params;

	/**
	 * @brief Puntatore a funzione che specifica la modalità di comunicazione
	 * con l'elaborazione.
	 *
	 * @param session la funzione deve ricevere come parametro la sessione da cui riceve l'aggiornamento.
	 * @param args deve essere possibile passare un argomento come notifica.
	 */
	void (*notify)(HostSession*session,void * args);

	/**
	 * @brief identifica l'elaborazione.
	 *
	 * Generalmente è il tid della thread che ha richiesto l'elaborazione.
	 */
	int keyElaboration;
} ElaborationEntity;

//////////////////////////////////////////////////////////////////////////////////////////////
////// Dichiarazione delle funzioni pubbliche delle sessioni con l'Host //////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

void Session_init(HostSession* session, int (*getReadFd)(), int (*getWriteFd)(),
		void (*update)(), void (*close)() );

bool Session_hasElaboration(HostSession* session);

int Session_getFDRead(HostSession* session);

int Session_getFDWrite(HostSession* session);

int Session_Write(HostSession* session,char *buf, int size);

int Session_Read(HostSession* session,char *buf, int size);

void Session_Update(HostSession* session);

void Session_addMyElaboration(HostSession* session);

void Session_addElaboration(HostSession* session, ElaborationEntity* elab);

void Session_delMyElaboration(HostSession* session);

void Session_delElaborationFor(HostSession* session, pthread_t tid);

void Session_lockSession(HostSession* session);

void Session_unlockSession(HostSession* session);

#endif /* SESSION_H_ */
